﻿using System;

namespace Aeon.Emulator.Video.Modes
{
    /// <summary>
    /// Implements functionality for chained 8-bit 256-color VGA modes.
    /// </summary>
    internal sealed class Vga256 : VideoMode
    {
        #region Constructors
        /// <summary>
        /// Initializes a new instance of the Vga256 class.
        /// </summary>
        /// <param name="width">Width of the display mode in pixels.</param>
        /// <param name="height">Height of the display mode in pixels.</param>
        /// <param name="video">Current VideoHandler instance.</param>
        public Vga256(int width, int height, VideoHandler video)
            : base(width, height, 8, false, 8, VideoModeType.Graphics, video)
        {
            unsafe
            {
                this.videoRam = (byte*)video.VideoRam.ToPointer();
            }
        }
        #endregion

        #region Public Methods
        /// <summary>
        /// Reads a byte from an address in video memory.
        /// </summary>
        /// <param name="offset">Address of byte to read.</param>
        /// <returns>Byte at specified address.</returns>
        internal override byte GetVramByte(uint offset)
        {
            unsafe
            {
                return videoRam[offset];
            }
        }
        /// <summary>
        /// Writes a byte to an address in video memory.
        /// </summary>
        /// <param name="offset">Address where byte will be written.</param>
        /// <param name="value">Value to write to specified address.</param>
        internal override void SetVramByte(uint offset, byte value)
        {
            unsafe
            {
                videoRam[offset] = value;
            }
        }
        /// <summary>
        /// Reads a 16-bit word from an address in video memory.
        /// </summary>
        /// <param name="offset">Address of word to read.</param>
        /// <returns>Word at specified address.</returns>
        internal override ushort GetVramWord(uint offset)
        {
            unsafe
            {
                return *(ushort*)(videoRam + offset);
            }
        }
        /// <summary>
        /// Writes a 16-bit word to an address in video memory.
        /// </summary>
        /// <param name="offset">Address where word will be written.</param>
        /// <param name="value">Value to write to specified address.</param>
        internal override void SetVramWord(uint offset, ushort value)
        {
            unsafe
            {
                *(ushort*)(videoRam + offset) = value;
            }
        }
        /// <summary>
        /// Reads a 32-bit doubleword from an address in video memory.
        /// </summary>
        /// <param name="offset">Address of doubleword to read.</param>
        /// <returns>Doubleword at specified address.</returns>
        internal override uint GetVramDWord(uint offset)
        {
            unsafe
            {
                return *(uint*)(videoRam + offset);
            }
        }
        /// <summary>
        /// Writes a 32-bit doubleword to an address in video memory.
        /// </summary>
        /// <param name="offset">Address where doubleword will be written.</param>
        /// <param name="value">Value to write to specified address.</param>
        internal override void SetVramDWord(uint offset, uint value)
        {
            unsafe
            {
                *(uint*)(videoRam + offset) = value;
            }
        }
        /// <summary>
        /// Writes a character at a position on the screen with the current font.
        /// </summary>
        /// <param name="x">Column of character to write.</param>
        /// <param name="y">Row of character to write.</param>
        /// <param name="index">Index of character to write.</param>
        /// <param name="foreground">Foreground color of character to write.</param>
        /// <param name="background">Background color of character to write.</param>
        internal override void WriteCharacter(int x, int y, int index, byte foreground, byte background)
        {
            //throw new NotImplementedException();
        }
        #endregion

        #region Private Fields
        private unsafe readonly byte* videoRam;
        #endregion
    }
}
